//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#include "ListAncestorMol.h"
#include "ListSmile.h"

#include <string.h>

#include <fstream>
#include <iostream>

#include <zlib.h>
#include <math.h>
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#define LENGHTINLINE 10000
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
using namespace std;
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
namespace SpaceListAncestor {

  bool FindFatherAncestor(TNode <AncestorMol>* NodeT, void* ref) {
    return (!strcmp(NodeT->Info()->ListIdAncestor()->GetFirst()->Out(), ((SmileStruct*)ref)->Id()))?true:false;
  }

  bool AscendentAncestor(TNode <AncestorMol>* NodeT, void* ref, void* parameters) {
    AncestorMol* ancestorA  = NodeT->Info();
    AncestorMol* ancestorB  = ((TNode <AncestorMol>*)ref)->Info();
    int          level      = (*(int*)parameters) - 1;
    return (*(ancestorA->ListIdAncestor()->Get(level)) < *(ancestorB->ListIdAncestor()->Get(level)))?true:false;
  }

  bool DescendentAncestor(TNode <AncestorMol>* NodeT, void* ref, void* parameters) {
    AncestorMol* ancestorA  = NodeT->Info();
    AncestorMol* ancestorB  = ((TNode <AncestorMol>*)ref)->Info();
    int          level      = (*(int*)parameters) - 1;
    return (*(ancestorA->ListIdAncestor()->Get(level)) > *(ancestorB->ListIdAncestor()->Get(level)))?true:false;
  }

  bool EqualAncestor(TNode <AncestorMol>* NodeT, void* ref, void* parameters) {
    AncestorMol* ancestorA  = NodeT->Info();
    AncestorMol* ancestorB  = ((TNode <AncestorMol>*)ref)->Info();
    int          level      = (*(int*)parameters) - 1;
    return (*(ancestorA->ListIdAncestor()->Get(level)) == *(ancestorB->ListIdAncestor()->Get(level)))?true:false;
  }

  bool EqualAncestor(TNode <AncestorMol>* NodeT, void* ref, void* parameterA, void* parameterB) {
    AncestorMol* ancestorA  = NodeT->Info();
    AncestorMol* ancestorB  = ((TNode <AncestorMol>*)ref)->Info();
    int          levelA     = (*(int*)parameterA) - 1;
    int          levelB     = (*(int*)parameterB) - 1;
    return (*(ancestorA->ListIdAncestor()->Get(levelA)) == *(ancestorB->ListIdAncestor()->Get(levelB)))?true:false;
  }

  bool DiffAncestor(TNode <AncestorMol>* NodeT, void* ref, void* parameters) {
    AncestorMol* ancestorA  = NodeT->Info();
    AncestorMol* ancestorB  = ((TNode <AncestorMol>*)ref)->Info();
    int          level      = (*(int*)parameters) - 1;

    //cout << "A- " << ancestorA->OutToAncestorString() << endl;
    //cout << "B- " << ancestorB->OutToAncestorString() << endl;
    
    if (*(ancestorA->ListIdAncestor()->Get(level)) != *(ancestorB->ListIdAncestor()->Get(level))) return false;
    else {
      if (*(ancestorA->ListIdAncestor()->Get(level)) == *(ancestorA->ListIdAncestor()->Get(0))) {
        NodeT->Info(NULL);
        NodeT->Info(ancestorB);
        ((TNode <AncestorMol>*)ref)->Info(NULL);
        ((TNode <AncestorMol>*)ref)->Info(ancestorA);
      }
      return true;
    }
  }

  bool EqualParents(TNode <AncestorMol>* NodeT, void* ref, void* parameters) {
    AncestorMol* ancestorA  = NodeT->Info();
    AncestorMol* ancestorB  = ((TNode <AncestorMol>*)ref)->Info();
    int          level      = (*(int*)parameters) - 1;
    return (*(ancestorA->ListIdAncestor()->Get(0)) == *(ancestorB->ListIdAncestor()->Get(level)))?true:false;
  }

  bool EqualChildren(TNode <AncestorMol>* NodeT, void* ref) {
    AncestorMol* ancestorA  = NodeT->Info();
    AncestorMol* ancestorB  = ((TNode <AncestorMol>*)ref)->Info();
    return (*(ancestorA->ListIdAncestor()->Get(0)) == *(ancestorB->ListIdAncestor()->Get(0)))?true:false;
  }

};
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
namespace SpaceSmileStruct {

  double ComputeLingoSim(TNode <SmileStruct>* NodeT, void* ref) {
    SmileStruct* smileStructA  = NodeT->Info();
    SmileStruct* smileStructB  = ((TNode <SmileStruct>*)ref)->Info();
    return smileStructA->ComputeLingoSimilarityWithoutNumber(smileStructB);
  }

  double EqualSmileStruct(TNode <SmileStruct>* NodeT, void* ref) {
    SmileStruct* smileStructA  = NodeT->Info();
    SmileStruct* smileStructB  = (SmileStruct*)ref;
    return *smileStructA == *smileStructB;
  }

};
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ListAncestorMol::ListAncestorMol():fileAncestorGZ(false), fileSmilesGZ(false) {
  this->filenameAncestor = new String();
  this->filenameSmiles   = new String();
  this->listAncestor     = new TListE <AncestorMol> ();
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ListAncestorMol::ListAncestorMol(String* filenameAncestor, String* filenameSmiles) {
  this->filenameAncestor = new String(filenameAncestor);
  this->filenameSmiles   = new String(filenameSmiles);
  this->listAncestor     = new TListE <AncestorMol> ();
  fileAncestorGZ         = (filenameAncestor->Contain("gz"))?true:false;
  fileSmilesGZ           = (filenameSmiles->Contain("gz"))?true:false;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ListAncestorMol::ListAncestorMol(ListAncestorMol& listAncestorMol) {
  this->filenameAncestor = new String(listAncestorMol.filenameAncestor);
  this->filenameSmiles   = new String(listAncestorMol.filenameSmiles);
  this->listAncestor     = new TListE <AncestorMol> (listAncestorMol.listAncestor);
  fileAncestorGZ         = (listAncestorMol.filenameAncestor->Contain("gz"))?true:false;
  fileSmilesGZ           = (listAncestorMol.filenameSmiles->Contain("gz"))?true:false;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ListAncestorMol::ListAncestorMol(ListAncestorMol* listAncestorMol) {
  this->filenameAncestor = new String(listAncestorMol->filenameAncestor);
  this->filenameSmiles   = new String(listAncestorMol->filenameSmiles);
  this->listAncestor     = new TListE <AncestorMol> (listAncestorMol->listAncestor);
  fileAncestorGZ         = (listAncestorMol->filenameAncestor->Contain("gz"))?true:false;
  fileSmilesGZ           = (listAncestorMol->filenameSmiles->Contain("gz"))?true:false;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ListAncestorMol::~ListAncestorMol() {
  if (this->filenameAncestor) delete this->filenameAncestor;
  if (this->filenameSmiles)   delete this->filenameSmiles;
  if (this->listAncestor)     delete this->listAncestor;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ListAncestorMol::FilenameAncestor(String* filenameAncestor) {
  this->filenameAncestor->In(filenameAncestor);
  fileAncestorGZ = (this->filenameAncestor->Contain("gz"))?true:false;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ListAncestorMol::FilenameAncestor(char* filenameAncestor) {
  this->filenameAncestor->In(filenameAncestor);
  fileAncestorGZ = (this->filenameAncestor->Contain("gz"))?true:false;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ListAncestorMol::FilenameSmiles(String* filenameSmiles) {
  this->filenameSmiles->In(filenameSmiles);
  fileSmilesGZ = (this->filenameSmiles->Contain("gz"))?true:false;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ListAncestorMol::FilenameSmiles(char* filenameSmiles) {
  this->filenameSmiles->In(filenameSmiles);
  fileSmilesGZ = (this->filenameSmiles->Contain("gz"))?true:false;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ListAncestorMol::ListAncestor(TListE <AncestorMol>* listAncestor) {
  *(this->listAncestor) = *listAncestor;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ListAncestorMol::FileAncestorGZ(bool fileAncestorGZ) {
  this->fileAncestorGZ = fileAncestorGZ;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ListAncestorMol::FileSmilesGZ(bool fileSmilesGZ) {
  this->fileSmilesGZ = fileSmilesGZ;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* ListAncestorMol::FilenameAncestor() {
  return this->filenameAncestor;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* ListAncestorMol::FilenameSmiles() {
  return this->filenameSmiles;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
TListE <AncestorMol>* ListAncestorMol::ListAncestor() {
  return this->listAncestor;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::FileAncestorGZ() {
  return this->fileAncestorGZ;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::FileSmilesGZ() {
  return this->fileSmilesGZ;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::LoadDataAncestorFiles() {
  
  if (!this->filenameAncestor->Length())  return false;

  ifstream ancestorFile;
  gzFile   ancestorFileGZ;
  
  String   lineInput;

  if (!this->fileAncestorGZ) ancestorFile.open(this->filenameAncestor->Out(), ios::in);
  else                       ancestorFileGZ = gzopen(this->filenameAncestor->Out(), "rb9");
  
  this->listAncestor->Clear();

  while (!((!this->fileAncestorGZ)?ancestorFile.eof():gzeof(ancestorFileGZ))) {

    char buffer[LENGHTINLINE + 1];

    if (!this->fileAncestorGZ) ancestorFile.getline(buffer, LENGHTINLINE);
    else                       gzgets(ancestorFileGZ, buffer, LENGHTINLINE);
    
    lineInput.In(buffer); lineInput.Trim();
    
    if (lineInput.Length()) {

      AncestorMol* ancestorMol = new AncestorMol();
      if (!ancestorMol) continue;
      ancestorMol->InputLineAncestor(lineInput);

      this->listAncestor->Add(ancestorMol);
      
    }
    
  }
  
  if (!this->fileAncestorGZ) ancestorFile.close();
  else                       gzclose(ancestorFileGZ);

  return true;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::LoadDataAncestorFilesFrom(long begin, long end) {

  if (!this->filenameAncestor->Length())  return false;

  ifstream ancestorFile;
  gzFile   ancestorFileGZ;

  String   lineInput;

  if (!this->fileAncestorGZ) {
    ancestorFile.open(this->filenameAncestor->Out(), ios::in);
    ancestorFile.seekg(begin, ios::beg);
  }
  else {
    ancestorFileGZ = gzopen(this->filenameAncestor->Out(), "rb9");
    gzseek(ancestorFileGZ, begin, SEEK_SET);
  }

  this->listAncestor->Clear();

  while (!((!this->fileAncestorGZ)?ancestorFile.eof():gzeof(ancestorFileGZ))) {

    char buffer[LENGHTINLINE + 1];

    if (!this->fileAncestorGZ) ancestorFile.getline(buffer, LENGHTINLINE);
    else                       gzgets(ancestorFileGZ, buffer, LENGHTINLINE);

    lineInput.In(buffer); lineInput.Trim();

    if (lineInput.Length()) {

      AncestorMol* ancestorMol = new AncestorMol();
      if (!ancestorMol) continue;
      ancestorMol->InputLineAncestor(lineInput);

      this->listAncestor->Add(ancestorMol);

    }
    
    if (!this->fileAncestorGZ) { if (ancestorFile.tellg()   > end) break; }
    else                       { if (gztell(ancestorFileGZ) > end) break; }

  }

  if (!this->fileAncestorGZ) ancestorFile.close();
  else                       gzclose(ancestorFileGZ);

  return true;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::LoadDataSmilesFiles() {

  if (!this->filenameSmiles->Length() || !this->listAncestor->Length())  return false;

  ifstream smileFile;
  gzFile   smileFileGZ;
  String   lineInput;

  if (!this->fileSmilesGZ) smileFile.open(this->filenameSmiles->Out(), ios::in);
  else                     smileFileGZ = gzopen(this->filenameSmiles->Out(), "rb9");

  while (!((!this->fileSmilesGZ)?smileFile.eof():gzeof(smileFileGZ))) {

    char buffer[LENGHTINLINE + 1];

    if (!this->fileSmilesGZ) smileFile.getline(buffer, LENGHTINLINE);
    else                     gzgets(smileFileGZ, buffer, LENGHTINLINE);

    lineInput.In(buffer); lineInput.Trim();

    if (lineInput.Length()) {

      SmileStruct* smile = new SmileStruct();
      smile->InputLine(lineInput);

      AncestorMol* ancestorMol = this->listAncestor->FirstOcurrence(SpaceListAncestor::FindFatherAncestor, smile);

      if (!ancestorMol) { delete smile; continue; }

      ancestorMol->Smile(smile);

      if (smile) delete smile;

    }

  }

  if (!this->fileSmilesGZ) smileFile.close();
  else                     gzclose(smileFileGZ);

  return true;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::LoadDataFiles() {

  if (!this->filenameAncestor->Length())  return false;

  ifstream ancestorFile;
  gzFile   ancestorFileGZ;

  String   lineInput;

  if (!this->fileAncestorGZ) ancestorFile.open(this->filenameAncestor->Out(), ios::in);
  else                       ancestorFileGZ = gzopen(this->filenameAncestor->Out(), "rb9");

  this->listAncestor->Clear();

  while (!((!this->fileAncestorGZ)?ancestorFile.eof():gzeof(ancestorFileGZ))) {

    char buffer[LENGHTINLINE + 1];

    if (!this->fileAncestorGZ) ancestorFile.getline(buffer, LENGHTINLINE);
    else                       gzgets(ancestorFileGZ, buffer, LENGHTINLINE);

    lineInput.In(buffer); lineInput.Trim();

    if (lineInput.Length()) {

      AncestorMol* ancestorMol = new AncestorMol();
      if (!ancestorMol) continue;
      ancestorMol->InputLineAncestor(lineInput);

      this->listAncestor->Add(ancestorMol);

    }

  }

  if (!this->fileAncestorGZ) ancestorFile.close();
  else                       gzclose(ancestorFileGZ);

  if (!this->filenameSmiles->Length()) {
    this->listAncestor->Clear();
    return false;
  }
  
  ifstream smileFile;
  gzFile   smileFileGZ;

  if (!this->fileSmilesGZ) smileFile.open(this->filenameSmiles->Out(), ios::in);
  else                     smileFileGZ = gzopen(this->filenameSmiles->Out(), "rb9");

  while (!((!this->fileSmilesGZ)?smileFile.eof():gzeof(smileFileGZ))) {

    char buffer[LENGHTINLINE + 1];

    if (!this->fileSmilesGZ) smileFile.getline(buffer, LENGHTINLINE);
    else                     gzgets(smileFileGZ, buffer, LENGHTINLINE);

    lineInput.In(buffer); lineInput.Trim();

    if (lineInput.Length()) {

      SmileStruct* smile = new SmileStruct();
      smile->InputLine(lineInput);

      AncestorMol* ancestorMol = this->listAncestor->FirstOcurrence(SpaceListAncestor::FindFatherAncestor, smile);

      if (!ancestorMol) { delete smile; continue; }

      ancestorMol->Smile(smile);

      if (smile) delete smile;

    }

  }

  if (!this->fileSmilesGZ) smileFile.close();
  else                     gzclose(smileFileGZ);

  return true;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::LoadDataFileFrom(long begin, long amount) {

  if (!this->filenameAncestor->Length() || begin < 0 || amount < 0)  return false;

  ifstream ancestorFile;
  gzFile   ancestorFileGZ;

  String   lineInput;
  long     count = 0;

  if (!this->fileAncestorGZ) ancestorFile.open(this->filenameAncestor->Out(), ios::in);
  else                       ancestorFileGZ = gzopen(this->filenameAncestor->Out(), "rb9");

  this->listAncestor->Clear();

  while (!((!this->fileAncestorGZ)?ancestorFile.eof():gzeof(ancestorFileGZ))) {

    char buffer[LENGHTINLINE + 1];

    if (!this->fileAncestorGZ) ancestorFile.getline(buffer, LENGHTINLINE);
    else                       gzgets(ancestorFileGZ, buffer, LENGHTINLINE);

    lineInput.In(buffer); lineInput.Trim();

    if (lineInput.Length()) {

      count++;

      if (count == begin) {
        AncestorMol* ancestorMol = new AncestorMol();
        if (!ancestorMol) continue;
        ancestorMol->InputLineAncestor(lineInput);
        this->listAncestor->Add(ancestorMol);
      }
      if ((count - begin) > amount) break;

    }

  }

  if (!this->fileAncestorGZ) ancestorFile.close();
  else                       gzclose(ancestorFileGZ);

  ifstream smileFile;
  gzFile   smileFileGZ;

  if (!this->fileSmilesGZ) smileFile.open(this->filenameSmiles->Out(), ios::in);
  else                     smileFileGZ = gzopen(this->filenameSmiles->Out(), "rb9");

  while (!((!this->fileSmilesGZ)?smileFile.eof():gzeof(smileFileGZ))) {

    char buffer[LENGHTINLINE + 1];

    if (!this->fileSmilesGZ) smileFile.getline(buffer, LENGHTINLINE);
    else                     gzgets(smileFileGZ, buffer, LENGHTINLINE);

    lineInput.In(buffer); lineInput.Trim();

    if (lineInput.Length()) {

      SmileStruct* smile = new SmileStruct();
      smile->InputLine(lineInput);

      AncestorMol* ancestorMol = this->listAncestor->FirstOcurrence(SpaceListAncestor::FindFatherAncestor, smile);

      if (!ancestorMol) { delete smile; continue; }

      ancestorMol->Smile(smile);

      if (smile) delete smile;

    }

  }

  if (!this->fileSmilesGZ) smileFile.close();
  else                     gzclose(smileFileGZ);

  return true;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::WriteAncestorFile() {

  fstream ancestorFile;
  gzFile  ancestorFileGZ;

  if (!this->fileAncestorGZ) ancestorFile.open(this->filenameAncestor->Out(), ios::out);
  else                       ancestorFileGZ = gzopen(this->filenameAncestor->Out(), "wb9");

  this->listAncestor->SetInitial();

  while (this->listAncestor->SetNext()) {

    char* textOut = this->listAncestor->GetCurrent()->OutToAncestorString();

    if (!this->fileAncestorGZ) ancestorFile << textOut << endl;
    else                       gzprintf(ancestorFileGZ, "%s\n", textOut);

    if (textOut) delete[] textOut;

  }

  if (!this->fileAncestorGZ) ancestorFile.close();
  else                       gzclose(ancestorFileGZ);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::WriteAncestorFileFrom(long begin, long amount) {

  fstream ancestorFile;
  gzFile   ancestorFileGZ;
  long     count = 0;

  if (!this->fileAncestorGZ) ancestorFile.open(this->filenameAncestor->Out(), ios::out);
  else                       ancestorFileGZ = gzopen(this->filenameAncestor->Out(), "wb9");

  this->listAncestor->SetPosition(begin);

  while (this->listAncestor->SetNext()) {

    char* textOut = this->listAncestor->GetCurrent()->OutToAncestorString();

    if (!this->fileAncestorGZ) ancestorFile << textOut << endl;
    else                       gzprintf(ancestorFileGZ, "%s\n", textOut);

    if (textOut) delete[] textOut;
    if (count++ > amount) break;

  }

  if (!this->fileAncestorGZ) ancestorFile.close();
  else                       gzclose(ancestorFileGZ);

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::WriteSmilesFile() {

  fstream smilesFile;
  gzFile  smilesFileGZ;

  if (!this->fileSmilesGZ) smilesFile.open(this->filenameSmiles->Out(), ios::out);
  else                     smilesFileGZ = gzopen(this->filenameSmiles->Out(), "wb9");

  this->listAncestor->SetInitial();
  while (this->listAncestor->SetNext()) {

    char* textOut = this->listAncestor->GetCurrent()->OutToSmileString();

    if (!this->fileSmilesGZ) smilesFile << textOut << endl;
    else                     gzprintf(smilesFileGZ, "%s\n", textOut);

    if (textOut) delete[] textOut;

  }

  if (!this->fileSmilesGZ) smilesFile.close();
  else                     gzclose(smilesFileGZ);

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::WriteSmilesFileFrom(long begin, long amount) {

  fstream smilesFile;
  gzFile  smilesFileGZ;
  long    count = 0;

  if (!this->fileSmilesGZ) smilesFile.open(this->filenameSmiles->Out(), ios::out);
  else                     smilesFileGZ = gzopen(this->filenameSmiles->Out(), "wb9");

  this->listAncestor->SetPosition(begin);
  while (this->listAncestor->SetNext()) {

    char* textOut = this->listAncestor->GetCurrent()->OutToSmileString();

    if (!this->fileSmilesGZ) smilesFile << textOut << endl;
    else                     gzprintf(smilesFileGZ, "%s\n", textOut);

    if (textOut) delete[] textOut;

    if (count++ > amount) break;

  }

  if (!this->fileSmilesGZ) smilesFile.close();
  else                     gzclose(smilesFileGZ);

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::WriteSmilesAncestorFile(int levelAncestor, String* filenameOut) {

  if (levelAncestor) {

    fstream smilesFile;
    gzFile  smilesFileGZ;

    if (!this->fileSmilesGZ) smilesFile.open(filenameOut->Out(), ios::out);
    else                     smilesFileGZ = gzopen(filenameOut->Out(), "wb9");

    TListE <AncestorMol> *representativeAncestorList = new TListE <AncestorMol>;

    this->listAncestor->RepresentativeOcurrencesAfterOrdered(SpaceListAncestor::DiffAncestor, representativeAncestorList, &levelAncestor);

    if (representativeAncestorList->Length()) {

      representativeAncestorList->SetInitial();

      while (representativeAncestorList->SetNext()) {
        AncestorMol* ancestorRepre = this->listAncestor->FirstOcurrence(SpaceListAncestor::EqualParents, representativeAncestorList->GetCurrentNode(), &levelAncestor);
        if (ancestorRepre) {
          char* textOut = ancestorRepre->OutToSmileString();
          if (!this->fileSmilesGZ) smilesFile << textOut << endl;
          else                     gzprintf(smilesFileGZ, "%s\n", textOut);
          if (textOut) delete[] textOut;
        }
      }

      representativeAncestorList->TransferAll();
    }

    if (representativeAncestorList) delete representativeAncestorList;

    if (!this->fileSmilesGZ) smilesFile.close();
    else                     gzclose(smilesFileGZ);

  }
  else {
    String tmp = *this->filenameSmiles;
    this->filenameSmiles->In(filenameOut);
    this->WriteSmilesFile();
    this->filenameSmiles->In(tmp);
  }

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::WriteSmilesAncestorFile(int levelAncestor, const char* filenameOut) {

  if (levelAncestor) {

    fstream smilesFile;
    gzFile  smilesFileGZ;

    if (!this->fileSmilesGZ) smilesFile.open(filenameOut, ios::out);
    else                     smilesFileGZ = gzopen(filenameOut, "wb9");

    TListE <AncestorMol> *representativeAncestorList = new TListE <AncestorMol>;

    this->listAncestor->RepresentativeOcurrencesAfterOrdered(SpaceListAncestor::DiffAncestor, representativeAncestorList, &levelAncestor);

    if (representativeAncestorList->Length()) {

      representativeAncestorList->SetInitial();

      while (representativeAncestorList->SetNext()) {
        AncestorMol* ancestorRepre = this->listAncestor->FirstOcurrence(SpaceListAncestor::EqualParents, representativeAncestorList->GetCurrentNode(), &levelAncestor);
        if (ancestorRepre) {
          char* textOut = ancestorRepre->OutToSmileString();
          if (!this->fileSmilesGZ) smilesFile << textOut << endl;
          else                     gzprintf(smilesFileGZ, "%s\n", textOut);
          if (textOut) delete[] textOut;
        }
      }

      representativeAncestorList->TransferAll();
    }

    if (representativeAncestorList) delete representativeAncestorList;

    if (!this->fileSmilesGZ) smilesFile.close();
    else                     gzclose(smilesFileGZ);

  }
  else {
    String tmp = *this->filenameSmiles;
    this->filenameSmiles->In(filenameOut);
    this->WriteSmilesFile();
    this->filenameSmiles->In(tmp);
  }

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
int ListAncestorMol::WriteClusterByAncestorFile(int levelAncestor, char* filenameOut) {

  int numberClusters = 0;
  if (levelAncestor < 1 || !filenameOut) return numberClusters;

  if (levelAncestor) {

    fstream smilesFile;
    gzFile  smilesFileGZ;
    int     count = 0;

    char*   pathBegin = strtok(filenameOut, ".");
    char*   pathEnd   = strtok(NULL, ".");

    TListE <AncestorMol> *representativeAncestorList = new TListE <AncestorMol>;

    this->listAncestor->RepresentativeOcurrencesAfterOrdered(SpaceListAncestor::DiffAncestor, representativeAncestorList, &levelAncestor);

    numberClusters = representativeAncestorList->Length();
    
    if (representativeAncestorList->Length()) {

      representativeAncestorList->SetInitial();

      while (representativeAncestorList->SetNext()) {

        TListE <AncestorMol> *clusterList = new TListE <AncestorMol>;

        this->listAncestor->AllOcurrence(SpaceListAncestor::EqualAncestor, clusterList, representativeAncestorList->GetCurrentNode(), &levelAncestor);

        if (clusterList->Length()) {

          char* tmpName = new char[strlen(filenameOut) + strlen("ClusterXXXXX") + 1];
          sprintf(tmpName, "%sCluster%05d\0", pathBegin, ++count);
          sprintf(tmpName, "%s.%s\0", tmpName, pathEnd);

          if (!this->fileSmilesGZ) smilesFile.open(tmpName, ios::out);
          else                     smilesFileGZ = gzopen(tmpName, "wb9");

          if (tmpName) delete[] tmpName;

          clusterList->SetInitial();

          while (clusterList->SetNext()) {

            char* textOut = clusterList->GetCurrent()->OutToSmileString();
            if (!this->fileSmilesGZ) smilesFile << textOut << endl;
            else                     gzprintf(smilesFileGZ, "%s\n", textOut);
            if (textOut) delete[] textOut;
            
          }

          if (!this->fileSmilesGZ) smilesFile.close();
          else                     gzclose(smilesFileGZ);

          clusterList->TransferAll();

        }

        if (clusterList) delete clusterList;

      }

      representativeAncestorList->TransferAll();
      
    }

    if (representativeAncestorList) delete representativeAncestorList;

  }

  return numberClusters;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
int ListAncestorMol::WriteClusterByAncestorFileInfo(int levelAncestor, char* filenameOut) {

  int numberClusters = 0;
  if (levelAncestor < 1 || !filenameOut) return numberClusters;

  if (levelAncestor) {

    fstream smilesFile;
    gzFile  smilesFileGZ;
    int     count = 0;

    char*   pathBegin = strtok(filenameOut, ".");
    char*   pathEnd   = strtok(NULL, ".");

    TListE <AncestorMol> *representativeAncestorList = new TListE <AncestorMol>;
    
    this->listAncestor->RepresentativeOcurrencesAfterOrdered(SpaceListAncestor::DiffAncestor, representativeAncestorList, &levelAncestor);

    numberClusters = representativeAncestorList->Length();

    if (representativeAncestorList->Length()) {

      representativeAncestorList->SetInitial();

      while (representativeAncestorList->SetNext()) {

        TListE <AncestorMol> *clusterList = new TListE <AncestorMol>;

        this->listAncestor->AllOcurrence(SpaceListAncestor::EqualAncestor, clusterList, representativeAncestorList->GetCurrentNode(), &levelAncestor);

        if (clusterList->Length()) {

          char* tmpName = new char[strlen(pathBegin) + strlen(pathEnd) + strlen("ClusterXXXXX") + 10];
          sprintf(tmpName, "%sCluster%05d\0", pathBegin, ++count);
          sprintf(tmpName, "%s.%s\0", tmpName, pathEnd);

          if (!this->fileSmilesGZ) smilesFile.open(tmpName, ios::out);
          else                     smilesFileGZ = gzopen(tmpName, "wb9");

          if (tmpName) delete[] tmpName;

          clusterList->SetInitial();

          while (clusterList->SetNext()) {

            char* textOut = clusterList->GetCurrent()->OutToSmileStringWithInfo();
            if (!this->fileSmilesGZ) smilesFile << textOut << endl;
            else                     gzprintf(smilesFileGZ, "%s\n", textOut);
            if (textOut) delete[] textOut;

          }

          if (!this->fileSmilesGZ) smilesFile.close();
          else                     gzclose(smilesFileGZ);

          clusterList->TransferAll();

        }

        if (clusterList) delete clusterList;

      }

      representativeAncestorList->TransferAll();

    }

    if (representativeAncestorList) delete representativeAncestorList;

  }

  return numberClusters;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ListAncestorMol::CenterListByLingoSim(TListE <AncestorMol>* representativeList, SmileStruct* center = NULL) {
  
  ListSmile* listAncestorSmiles  = new ListSmile();

  representativeList->SetInitial();
  while (representativeList->SetNext()) {
    SmileStruct *smile = new SmileStruct();
    *smile = *(representativeList->GetCurrent()->Smile());
    listAncestorSmiles->AllSmiles()->Add(smile);
  }

  if (!center) {

    listAncestorSmiles->ObtainSimilarityMatrixWithoutNumber();
    listAncestorSmiles->ObtainAverageSimMatrix();

    double maxAverage = listAncestorSmiles->AverageSimDistance()[0];
    long   position   = 0;

    for (int i = 0; i < listAncestorSmiles->AllSmiles()->Length(); i++)
      if (listAncestorSmiles->AverageSimDistance()[i] > maxAverage) {
        maxAverage = listAncestorSmiles->AverageSimDistance()[i];
        position   = i;
      }
    
    center = listAncestorSmiles->AllSmiles()->Get(position);

  }

  TNode <SmileStruct>* centerNode = new TNode <SmileStruct> ();
  
  centerNode->Info(center);

  listAncestorSmiles->AllSmiles()->OrderListCentered(SpaceSmileStruct::ComputeLingoSim, centerNode);

  for (int i = 0, k = 0; i < listAncestorSmiles->AllSmiles()->Length(); i++)
    for (int j = k; j < representativeList->Length(); j++)
      if (SpaceSmileStruct::EqualSmileStruct(listAncestorSmiles->AllSmiles()->GetNode(i), representativeList->GetNode(j)->Info()->Smile())) {

        AncestorMol* temporal = representativeList->GetNode(k)->Info();
        representativeList->GetNode(k)->Info(NULL);
        representativeList->GetNode(k++)->Info(representativeList->GetNode(j)->Info());
        representativeList->GetNode(j)->Info(NULL);
        representativeList->GetNode(j)->Info(temporal);

      }

  centerNode->Info(NULL);

  if (centerNode)         delete centerNode;
  if (listAncestorSmiles) delete listAncestorSmiles;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ListAncestorMol::ListOriginalAncestor(TListE <AncestorMol>* ancestorList, TListE <AncestorMol>* representativeList, int level) {

  AncestorMol* originalAncestor = NULL;

  representativeList->Clear();

  cout << " - " << ancestorList->Length() << endl;

  ancestorList->SetInitial();
  while (ancestorList->SetNext()) {

    if (representativeList->Length()) {
      originalAncestor = representativeList->FirstOcurrence(SpaceListAncestor::EqualParents, ancestorList->GetCurrentNode(), &level);
      if (originalAncestor) continue;
    }

    originalAncestor = this->listAncestor->FirstOcurrence(SpaceListAncestor::EqualParents, ancestorList->GetCurrentNode(), &level);
    if (originalAncestor) representativeList->Add(originalAncestor);
    
  }
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::OrderListByAncestorCenteredIterative() {

  int                   level              = this->listAncestor->GetFirst()->ListIdAncestor()->Length();
  TListE <AncestorMol>* repreAncestorList  = new TListE <AncestorMol> ();
  TListE <AncestorMol>* representativeList = new TListE <AncestorMol> ();

  this->listAncestor->RepresentativeOcurrences(SpaceListAncestor::DiffAncestor, repreAncestorList, &level);

  this->ListOriginalAncestor(repreAncestorList, representativeList, level);

  repreAncestorList->TransferAll();
  if (repreAncestorList) delete repreAncestorList;

  cout << representativeList->Length() << endl;

  cout << "Center By LINGOSim" << endl;
  this->CenterListByLingoSim(representativeList, NULL);

  cout << "Order complete list by list ordered using LINGOSim" << endl;
  this->listAncestor->OrderListByList(SpaceListAncestor::EqualAncestor, representativeList, &level);

  cout << "Start the level analysis" << endl;
  for (long i = level; i > 1; i--) {

    level--;

    if (i != this->listAncestor->GetFirst()->ListIdAncestor()->Length()) {
      
      TListE <AncestorMol>* repreAncestorList  = new TListE <AncestorMol> ();

      this->listAncestor->RepresentativeOcurrences(SpaceListAncestor::EqualAncestor, repreAncestorList, &i);

      this->ListOriginalAncestor(repreAncestorList, representativeList, i);

      repreAncestorList->TransferAll();
      if (repreAncestorList) delete repreAncestorList;
      
    }
    
    if (representativeList->Length()) {

      representativeList->SetInitial();

      while (representativeList->SetNext()) {

        TListE <AncestorMol>* childrenList = new TListE <AncestorMol> ();

        this->listAncestor->ConsecutiveSubList(SpaceListAncestor::EqualAncestor, childrenList, representativeList->GetCurrentNode(), &i);

        if (childrenList->Length()) {

          TListE <AncestorMol>* representativeChildrenList  = new TListE <AncestorMol> ();

          if (level > 1) {
            
            TListE <AncestorMol>* repreChildrenAncestorList  = new TListE <AncestorMol> ();

            childrenList->RepresentativeOcurrences(SpaceListAncestor::EqualAncestor, repreChildrenAncestorList, &level);

            this->ListOriginalAncestor(repreChildrenAncestorList, representativeChildrenList, level);

            repreChildrenAncestorList->TransferAll();
            if (repreChildrenAncestorList) delete repreChildrenAncestorList;
            
          }
          else *(representativeChildrenList) = *(childrenList);

          this->CenterListByLingoSim(representativeChildrenList, representativeList->GetCurrent()->Smile());

          childrenList->OrderListByList(SpaceListAncestor::EqualAncestor, representativeChildrenList, &level);

          representativeChildrenList->TransferAll();
          if (representativeChildrenList) delete representativeChildrenList;

          childrenList->CleanConsecutiveSubList();

        }

        if (childrenList) delete childrenList;

      }

    }

    representativeList->TransferAll();

  }
  
  if (representativeList) delete representativeList;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::OrderListByAncestorCenteredIterativeX() {

  int                   level              = this->listAncestor->GetFirst()->ListIdAncestor()->Length();
  int                   size               = level;
  TListE <AncestorMol>* representativeList = new TListE <AncestorMol> ();

  this->listAncestor->QuickSortList(SpaceListAncestor::AscendentAncestor, NULL, &size);
  this->listAncestor->RepresentativeOcurrencesAfterOrdered(SpaceListAncestor::DiffAncestor, representativeList, &size);

  this->CenterListByLingoSim(representativeList, NULL);
  this->listAncestor->OrderListByList(SpaceListAncestor::EqualAncestor, representativeList, &size);

  for (long i = level; i > 1; i--) {

    level--;

    if (representativeList->Length()) {

      representativeList->SetInitial();
      while (representativeList->SetNext()) {

        TListE <AncestorMol>* childrenList = new TListE <AncestorMol> ();
        this->listAncestor->AllOcurrence(SpaceListAncestor::EqualAncestor, childrenList, representativeList->GetCurrentNode(), &i);

        if (childrenList->Length() > 1) {

          TListE <AncestorMol>* representativeChildrenList  = new TListE <AncestorMol> ();
          int levelOrder = level - 1;
          if (level > 1) {
            childrenList->QuickSortList(SpaceListAncestor::AscendentAncestor, NULL, &levelOrder);
            childrenList->RepresentativeOcurrencesAfterOrdered(SpaceListAncestor::DiffAncestor, representativeChildrenList, &level);
          }
          else           *(representativeChildrenList) = *(childrenList);

          this->CenterListByLingoSim(representativeChildrenList, representativeList->GetCurrent()->Smile());
          childrenList->OrderListByList(SpaceListAncestor::EqualAncestor, representativeChildrenList, &level);

          representativeChildrenList->TransferAll();
          if (representativeChildrenList) delete representativeChildrenList;

        }
        
        childrenList->TransferAll();
        if (childrenList) delete childrenList;
        
      }

    }

    representativeList->TransferAll();
    if (level > 1) this->listAncestor->RepresentativeOcurrencesAfterOrdered(SpaceListAncestor::DiffAncestor, representativeList, &i);

  }

  representativeList->TransferAll();
  if (representativeList) delete representativeList;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::OrderListByAncestorAscendentIterative() {

  int level = this->listAncestor->GetFirst()->ListIdAncestor()->Length();

  this->listAncestor->QuickSortList(SpaceListAncestor::AscendentAncestor, NULL, &level);

  for (int i = this->listAncestor->GetFirst()->ListIdAncestor()->Length(); i > 1; i--) {

    level--;
    TListE <AncestorMol>* representativeList = new TListE <AncestorMol> ();
    this->listAncestor->RepresentativeOcurrencesAfterOrdered(SpaceListAncestor::EqualAncestor, representativeList, &i);

    if (representativeList->Length()) {

      representativeList->SetInitial();

      while (representativeList->SetNext()) {

        TListE <AncestorMol>* childrenList = new TListE <AncestorMol> ();

        this->listAncestor->ConsecutiveSubList(SpaceListAncestor::EqualAncestor, childrenList, representativeList->GetCurrentNode(), &i);

        if (childrenList->Length()) {
          childrenList->QuickSortList(SpaceListAncestor::AscendentAncestor, NULL, &level);
          childrenList->CleanConsecutiveSubList();
        }

        if (childrenList) delete childrenList;

      }

      representativeList->TransferAll();

    }

    if (representativeList) delete representativeList;

  }

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::OrderListByAncestorDescendentIterative() {

  int level = this->listAncestor->GetFirst()->ListIdAncestor()->Length();

  this->listAncestor->QuickSortList(SpaceListAncestor::DescendentAncestor, NULL, &level);

  for (int i = this->listAncestor->GetFirst()->ListIdAncestor()->Length(); i > 1; i--) {

    level--;
    TListE <AncestorMol>* representativeList = new TListE <AncestorMol> ();
    this->listAncestor->RepresentativeOcurrencesAfterOrdered(SpaceListAncestor::EqualAncestor, representativeList, &i);

    if (representativeList->Length()) {

      representativeList->SetInitial();

      while (representativeList->SetNext()) {

        TListE <AncestorMol>* childrenList = new TListE <AncestorMol> ();

        this->listAncestor->ConsecutiveSubList(SpaceListAncestor::EqualAncestor, childrenList, representativeList->GetCurrentNode(), &i);
        
        if (childrenList->Length()) {
          childrenList->QuickSortList(SpaceListAncestor::DescendentAncestor, NULL, &level);
          childrenList->CleanConsecutiveSubList();
        }

        if (childrenList) delete childrenList;

      }

      representativeList->TransferAll();

    }

    if (representativeList) delete representativeList;

  }

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::OrderListByAncestorCentered() {

  int                   level              = this->listAncestor->GetFirst()->ListIdAncestor()->Length();
  TListE <AncestorMol>* repreAncestorList  = new TListE <AncestorMol> ();
  TListE <AncestorMol>* representativeList = new TListE <AncestorMol> ();

  this->listAncestor->RepresentativeOcurrences(SpaceListAncestor::EqualAncestor, repreAncestorList, &level);
  this->ListOriginalAncestor(repreAncestorList, representativeList, level);

  repreAncestorList->TransferAll();
  if (repreAncestorList) delete repreAncestorList;

  if (representativeList->Length()) {

    this->CenterListByLingoSim(representativeList, NULL);
    this->listAncestor->OrderListByList(SpaceListAncestor::EqualAncestor, representativeList, &level);

    representativeList->SetInitial();

    while (representativeList->SetNext()) {

      TListE <AncestorMol>* childrenList = new TListE <AncestorMol> ();

      this->listAncestor->ConsecutiveSubList(SpaceListAncestor::EqualAncestor, childrenList, representativeList->GetCurrentNode(), &level);

      if (childrenList->Length()) {

        int levelBefore = level - 1;

        TListE <AncestorMol>* repreChildrenAncestorList  = new TListE <AncestorMol> ();
        childrenList->RepresentativeOcurrences(SpaceListAncestor::EqualAncestor, repreChildrenAncestorList, &levelBefore);

        TListE <AncestorMol>* representativeChildrenList  = new TListE <AncestorMol> ();
        this->ListOriginalAncestor(repreChildrenAncestorList, representativeChildrenList, levelBefore);

        repreChildrenAncestorList->TransferAll();
        if (repreChildrenAncestorList) delete repreChildrenAncestorList;

        this->CenterListByLingoSim(representativeChildrenList, representativeList->GetCurrent()->Smile());

        childrenList->OrderListByList(SpaceListAncestor::EqualAncestor, representativeChildrenList, &levelBefore);

        representativeChildrenList->TransferAll();
        if (representativeChildrenList) delete representativeChildrenList;

        childrenList->CleanConsecutiveSubList();

      }

      if (childrenList) delete childrenList;

    }

  }

  representativeList->TransferAll();
  if (representativeList) delete representativeList;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::OrderListByAncestorAscendent() {

  int level = this->listAncestor->GetFirst()->ListIdAncestor()->Length();
  this->listAncestor->QuickSortList(SpaceListAncestor::AscendentAncestor, NULL, &level);

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListAncestorMol::OrderListByAncestorDescendent() {

  int level = this->listAncestor->GetFirst()->ListIdAncestor()->Length();
  this->listAncestor->QuickSortList(SpaceListAncestor::DescendentAncestor, NULL, &level);

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
double ListAncestorMol::ComputeConvergenceAncestorFile(String* referenceFile) {

  if (!referenceFile->Length()) return 0;

  TListE <AncestorMol>* listReferenceAncestor = new TListE <AncestorMol> ();

  ifstream              ancestorFile;
  gzFile                ancestorFileGZ;

  bool                  refFileGZ             = (referenceFile->Contain("gz"))?true:false;
  
  String                lineInput;

  if (!refFileGZ) ancestorFile.open(referenceFile->Out(), ios::in);
  else            ancestorFileGZ = gzopen(referenceFile->Out(), "rb9");

  while (!((!refFileGZ)?ancestorFile.eof():gzeof(ancestorFileGZ))) {

    char buffer[LENGHTINLINE + 1];

    if (!refFileGZ) ancestorFile.getline(buffer, LENGHTINLINE);
    else            gzgets(ancestorFileGZ, buffer, LENGHTINLINE);

    lineInput.In(buffer); lineInput.Trim();

    if (lineInput.Length()) {

      AncestorMol* ancestorMol = new AncestorMol();
      if (!ancestorMol) continue;
      ancestorMol->InputLineAncestor(lineInput);

      listReferenceAncestor->Add(ancestorMol);

    }

  }

  if (!refFileGZ) ancestorFile.close();
  else            gzclose(ancestorFileGZ);

  double                factor  = 0;
  int                   level   = 2;

  TNode  <AncestorMol>* refNode = this->listAncestor->GetFirstNode();

  for (long i = 0; i < this->listAncestor->Length(); i++, refNode = refNode->Next()) {

    TListE <AncestorMol>* childrenList = new TListE <AncestorMol> ();
    
    this->listAncestor->AllOcurrence(SpaceListAncestor::EqualAncestor, childrenList, refNode, &level);

    if (childrenList->Length()) {

      TListE <AncestorMol>* childrenRefList = new TListE <AncestorMol> ();

      listReferenceAncestor->AllOcurrence(SpaceListAncestor::EqualAncestor, childrenRefList, refNode, &level);

      if (childrenRefList->Length()) {

        long commonMolecules = 0;
        
        TNode  <AncestorMol>* commonNode = childrenRefList->GetFirstNode();

        for (long j = 0; j < childrenRefList->Length(); j++, commonNode = commonNode->Next())
          if (childrenList->FirstOcurrence(SpaceListAncestor::EqualChildren, commonNode))
            commonMolecules++;

        factor += ((double)((double)commonMolecules/(double)childrenRefList->Length()));

        childrenRefList->TransferAll();

      }

      if (childrenRefList) delete childrenRefList;
       
      childrenList->TransferAll();
      
    }

    if (childrenList) delete childrenList;
    
  }

  factor /= ((double)listReferenceAncestor->Length());

  if (listReferenceAncestor) delete listReferenceAncestor;
  
  return factor;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
double ListAncestorMol::ComputeConvergenceClusterSim(String* referenceFile) {

  if (!referenceFile->Length()) return 0;

  TListE <AncestorMol>* listReferenceAncestor = new TListE <AncestorMol> ();

  ifstream              ancestorFile;
  gzFile                ancestorFileGZ;
  bool                  refFileGZ             = (referenceFile->Contain("gz"))?true:false;
  String                lineInput;

  if (!refFileGZ) ancestorFile.open(referenceFile->Out(), ios::in);
  else            ancestorFileGZ = gzopen(referenceFile->Out(), "rb9");

  while (!((!refFileGZ)?ancestorFile.eof():gzeof(ancestorFileGZ))) {

    char buffer[LENGHTINLINE + 1];

    if (!refFileGZ) ancestorFile.getline(buffer, LENGHTINLINE);
    else            gzgets(ancestorFileGZ, buffer, LENGHTINLINE);

    lineInput.In(buffer); lineInput.Trim();

    if (lineInput.Length()) {

      AncestorMol* ancestorMol = new AncestorMol();
      if (!ancestorMol) continue;
      ancestorMol->InputLineAncestor(lineInput);

      listReferenceAncestor->Add(ancestorMol);

    }

  }

  if (!refFileGZ) ancestorFile.close();
  else            gzclose(ancestorFileGZ);

  double                factorRef  = 0;
  double                factorOwn  = 0;
  int                   level      = 2;

  TNode  <AncestorMol>* refNode = this->listAncestor->GetFirstNode();

  for (long i = 0; i < this->listAncestor->Length(); i++, refNode = refNode->Next()) {
    
    TListE <AncestorMol>* childrenList = new TListE <AncestorMol> ();
    
    this->listAncestor->AllOcurrence(SpaceListAncestor::EqualAncestor, childrenList, refNode, &level);
    
    if (childrenList->Length()) {

      TListE <AncestorMol>* childrenRefList = new TListE <AncestorMol> ();

      listReferenceAncestor->AllOcurrence(SpaceListAncestor::EqualAncestor, childrenRefList, refNode, &level);

      if (childrenRefList->Length()) {

        long commonMolecules = 0;

        TNode  <AncestorMol>* commonNode = childrenRefList->GetFirstNode();

        for (long j = 0; j < childrenRefList->Length(); j++, commonNode = commonNode->Next()) 
          if (childrenList->FirstOcurrence(SpaceListAncestor::EqualChildren, commonNode))
            commonMolecules++;

        factorRef += ((commonMolecules - 1)/(childrenList->Length() + childrenRefList->Length() - commonMolecules));
        factorOwn += ((childrenList->Length() - 1)/(childrenList->Length()));

        childrenRefList->TransferAll();

      }
      else {

        factorRef += ((-1)/(childrenList->Length()));
        factorOwn += ((childrenList->Length() - 1)/(childrenList->Length()));
        
      }

      if (childrenRefList) delete childrenRefList;

      childrenList->TransferAll();

    }

    if (childrenList) delete childrenList;
    
  }

  if (listReferenceAncestor) delete listReferenceAncestor;

  return factorRef/factorOwn;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
double ListAncestorMol::ComputeSumConvergenceAncestorFile(String* referenceFile, long& numberCompounds) {

  if (!referenceFile->Length()) return 0;

  TListE <AncestorMol>* listReferenceAncestor = new TListE <AncestorMol> ();

  ifstream              ancestorFile;
  gzFile                ancestorFileGZ;

  bool                  refFileGZ             = (referenceFile->Contain("gz"))?true:false;

  String                lineInput;

  if (!refFileGZ) ancestorFile.open(referenceFile->Out(), ios::in);
  else            ancestorFileGZ = gzopen(referenceFile->Out(), "rb9");

  while (!((!refFileGZ)?ancestorFile.eof():gzeof(ancestorFileGZ))) {

    char buffer[LENGHTINLINE + 1];

    if (!refFileGZ) ancestorFile.getline(buffer, LENGHTINLINE);
    else            gzgets(ancestorFileGZ, buffer, LENGHTINLINE);

    lineInput.In(buffer); lineInput.Trim();

    if (lineInput.Length()) {

      AncestorMol* ancestorMol = new AncestorMol();
      if (!ancestorMol) continue;
      ancestorMol->InputLineAncestor(lineInput);

      listReferenceAncestor->Add(ancestorMol);

    }

  }

  if (!refFileGZ) ancestorFile.close();
  else            gzclose(ancestorFileGZ);

  double                factor  = 0;
  int                   level   = 2;

  TNode  <AncestorMol>* refNode = this->listAncestor->GetFirstNode();

  for (long i = 0; i < this->listAncestor->Length(); i++, refNode = refNode->Next()) {

    TListE <AncestorMol>* childrenList = new TListE <AncestorMol> ();

    this->listAncestor->AllOcurrence(SpaceListAncestor::EqualAncestor, childrenList, refNode, &level);

    if (childrenList->Length()) {

      TListE <AncestorMol>* childrenRefList = new TListE <AncestorMol> ();

      listReferenceAncestor->AllOcurrence(SpaceListAncestor::EqualAncestor, childrenRefList, refNode, &level);

      if (childrenRefList->Length()) {

        long commonMolecules = 0;

        TNode  <AncestorMol>* commonNode = childrenRefList->GetFirstNode();

        for (long j = 0; j < childrenRefList->Length(); j++, commonNode = commonNode->Next())
          if (childrenList->FirstOcurrence(SpaceListAncestor::EqualChildren, commonNode))
            commonMolecules++;

        factor += ((double)((double)commonMolecules/(double)childrenRefList->Length()));

        childrenRefList->TransferAll();

      }

      if (childrenRefList) delete childrenRefList;

      childrenList->TransferAll();

    }

    if (childrenList) delete childrenList;

  }

  numberCompounds = listReferenceAncestor->Length();

  if (listReferenceAncestor) delete listReferenceAncestor;

  return factor;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
double ListAncestorMol::ComputeSumConvergenceClusterSim(String* referenceFile, double& factorRef, double& factorOwn) {

  if (!referenceFile->Length()) return 0;

  TListE <AncestorMol>* listReferenceAncestor = new TListE <AncestorMol> ();

  ifstream              ancestorFile;
  gzFile                ancestorFileGZ;
  bool                  refFileGZ             = (referenceFile->Contain("gz"))?true:false;
  String                lineInput;

  if (!refFileGZ) ancestorFile.open(referenceFile->Out(), ios::in);
  else            ancestorFileGZ = gzopen(referenceFile->Out(), "rb9");

  while (!((!refFileGZ)?ancestorFile.eof():gzeof(ancestorFileGZ))) {

    char buffer[LENGHTINLINE + 1];

    if (!refFileGZ) ancestorFile.getline(buffer, LENGHTINLINE);
    else            gzgets(ancestorFileGZ, buffer, LENGHTINLINE);

    lineInput.In(buffer); lineInput.Trim();

    if (lineInput.Length()) {

      AncestorMol* ancestorMol = new AncestorMol();
      if (!ancestorMol) continue;
      ancestorMol->InputLineAncestor(lineInput);

      listReferenceAncestor->Add(ancestorMol);

    }

  }

  if (!refFileGZ) ancestorFile.close();
  else            gzclose(ancestorFileGZ);

  factorRef = 0;
  factorOwn = 0;
  
  int level = 2;

  TNode  <AncestorMol>* refNode = this->listAncestor->GetFirstNode();

  for (long i = 0; i < this->listAncestor->Length(); i++, refNode = refNode->Next()) {

    TListE <AncestorMol>* childrenList = new TListE <AncestorMol> ();

    this->listAncestor->AllOcurrence(SpaceListAncestor::EqualAncestor, childrenList, refNode, &level);

    if (childrenList->Length()) {

      TListE <AncestorMol>* childrenRefList = new TListE <AncestorMol> ();

      listReferenceAncestor->AllOcurrence(SpaceListAncestor::EqualAncestor, childrenRefList, refNode, &level);

      if (childrenRefList->Length()) {

        long commonMolecules = 0;

        TNode  <AncestorMol>* commonNode = childrenRefList->GetFirstNode();

        for (long j = 0; j < childrenRefList->Length(); j++, commonNode = commonNode->Next())
          if (childrenList->FirstOcurrence(SpaceListAncestor::EqualChildren, commonNode))
            commonMolecules++;

        factorRef += (double)((double)(commonMolecules - 1)/(double)(childrenList->Length() + childrenRefList->Length() - commonMolecules));
        factorOwn += (double)((double)(childrenList->Length() - 1)/(double)(childrenList->Length()));

        childrenRefList->TransferAll();

      }
      else {

        factorRef += ((double)(-1)/(double)(childrenList->Length()));
        factorOwn += ((double)(childrenList->Length() - 1)/(double)(childrenList->Length()));

      }

      if (childrenRefList) delete childrenRefList;

      childrenList->TransferAll();

    }

    if (childrenList) delete childrenList;

  }

  if (listReferenceAncestor) delete listReferenceAncestor;
  
  return factorRef/factorOwn;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
double ListAncestorMol::ComputeClusterSimilarity(String* referenceFile, int levelA, int levelB) {

  if (!referenceFile->Length()) return 0;

  ListAncestorMol* listReferenceAncestor = new ListAncestorMol();

  listReferenceAncestor->FilenameAncestor(referenceFile);
  listReferenceAncestor->LoadDataAncestorFiles();

  double similarity = 0;

  TNode  <AncestorMol>* refNode      = this->listAncestor->GetFirstNode();
  TListE <AncestorMol>* childrenList = new TListE <AncestorMol> ();

  for (long i = 0; i < this->listAncestor->Length(); i++, refNode = refNode->Next()) {

    childrenList->TransferAll();
    this->listAncestor->AllOcurrence(SpaceListAncestor::EqualAncestor, childrenList, refNode, &levelA);

    if (childrenList->Length()) {

      TListE <AncestorMol>* childrenRefList = new TListE <AncestorMol> ();
      TNode  <AncestorMol>* searchNode      = new TNode <AncestorMol> ();

      AncestorMol* searchMol = listReferenceAncestor->ListAncestor()->FirstOcurrence(SpaceListAncestor::EqualChildren, refNode);
      if (searchMol) {
        searchNode->Info(searchMol);
        listReferenceAncestor->ListAncestor()->AllOcurrence(SpaceListAncestor::EqualAncestor, childrenRefList, searchNode, &levelB);
        searchNode->Info(NULL);
      }

      if (searchNode) delete searchNode;

      if (childrenRefList->Length()) {

        long                  commonMolecules = 0;
        TNode  <AncestorMol>* commonNode      = childrenRefList->GetFirstNode();

        for (long j = 0; j < childrenRefList->Length(); j++, commonNode = commonNode->Next())
          if (childrenList->FirstOcurrence(SpaceListAncestor::EqualChildren, commonNode))
            commonMolecules++;

        similarity += (double)((double)(commonMolecules)/(double)(childrenList->Length() + childrenRefList->Length() - commonMolecules));

        childrenRefList->TransferAll();

      }

      if (childrenRefList) delete childrenRefList;

      childrenList->TransferAll();

    }

  }

  if (childrenList)          delete childrenList;
  if (listReferenceAncestor) delete listReferenceAncestor;

  return similarity/(double)(this->listAncestor->Length());

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ListAncestorMol ListAncestorMol::operator=(ListAncestorMol& listAncestorMol) {

  *(this->filenameAncestor) = *(listAncestorMol.filenameAncestor);
  *(this->filenameSmiles)   = *(listAncestorMol.filenameSmiles);
  *(this->listAncestor)     = *(listAncestorMol.listAncestor);

  this->fileAncestorGZ      = listAncestorMol.fileAncestorGZ;
  this->fileSmilesGZ        = listAncestorMol.fileSmilesGZ;

  return *this;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
